﻿using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Core.Framework
{
    public class iToolFileChangeDetect
    {
        /// <summary>
        /// 定时器触发间隔
        /// </summary>
        private int TimeoutMillis { get; set; }
        private string Directory { get; set; }
        private string FilterType { get; set; }
        private string FilePath { get; set; }
        private Func<string, bool> Event { get; set; }
        private readonly FileSystemWatcher watcher = new FileSystemWatcher();
        private readonly Timer Timer = null;
        readonly ManualResetEvent manual = new ManualResetEvent(false);


        public iToolFileChangeDetect(string filePath) : this(filePath, 1000)
        {

        }

        public iToolFileChangeDetect(string filePath, int timeoutMillis)
        {
            Timer = new Timer(new TimerCallback(OnWatchedFileChange), null, Timeout.Infinite, Timeout.Infinite);
            this.TimeoutMillis = timeoutMillis;
            this.Directory = Path.GetDirectoryName(filePath);
            this.FilterType = $"*{Path.GetExtension(filePath)}";
            this.FilePath = filePath;
            this.WatcherStart();
        }

        /// <summary>
        /// 初始化监听
        /// </summary>
        /// <param name="directory">需要监听的目录</param>
        /// <param name="filterType">需要监听的文件类型(筛选器字符串)</param>
        /// <param name="IsEnableRaising">是否启用监听</param>
        /// <param name="IsInclude">是否监听子目录</param>
        private void WatcherStart()
        {
            watcher.BeginInit();
            watcher.Filter = FilterType;
            watcher.IncludeSubdirectories = false;
            watcher.EnableRaisingEvents = true;
            watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
            watcher.Path = this.Directory;

            watcher.Changed += (sender, e) =>
            {
                if (e.FullPath == Path.GetFullPath(this.FilePath))
                {
                    Timer.Change(TimeoutMillis, Timeout.Infinite);
                }
            };

            watcher.EndInit();
        }

        public void Stop()
        {
            manual.Set();
        }

        public void StartWaitResult(Func<string, bool> action, int maxWaitTime = -1)
        {
            try
            {
                this.Event = action;
                string content = string.Empty;
                try
                {
                    content = File.ReadAllText(this.FilePath);
                }
                catch
                {
                }

                LoggerUtils.Write($"call ： {content} - {Event.Invoke(content)} - {this.FilePath}", "log_service");


                if (Event.Invoke(content))
                {
                    this.Stop();
                }
                else
                {
                    manual.Reset();

                    if (maxWaitTime > 0)
                    {
                        Task.Run(async () =>
                        {
                            await Task.Delay(maxWaitTime);
                            manual.Set();
                        });
                    }
                    manual.WaitOne();
                }
            }
            catch (Exception ex)
            {
                LoggerUtils.Write($"call error： {ex.TryToJson()}", "log_service");
            }
        }

        private void OnWatchedFileChange(object state)
        {
            bool result = false;

            if (File.Exists(this.FilePath))
            {
                var content = File.ReadAllText(this.FilePath);
                result = Event.Invoke(content);
            }
            else
            {
                result = Event.Invoke(string.Empty);
            }

            LoggerUtils.Write($"call OnWatchedFileChange： {File.ReadAllText(this.FilePath)} - {result} - {this.FilePath}", "log_service");


            if (result)
            {
                this.Stop();
            }
        }
    }
}


